package com.david.func_test.widget

import android.animation.ValueAnimator
import android.app.Activity
import android.content.res.Resources
import android.util.DisplayMetrics
import android.util.Log
import android.util.TypedValue
import android.view.MotionEvent
import android.view.View
import android.view.animation.LinearInterpolator
import android.widget.FrameLayout
import android.widget.ImageView
import androidx.core.animation.doOnEnd
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSnapHelper
import androidx.recyclerview.widget.RecyclerView
import com.david.func_test.R
import com.google.android.material.bottomsheet.BottomSheetBehavior
import kotlin.math.abs

class DragFloatWidget {
    /**
     * 悬浮父控件
     */
    var parent:FrameLayout
    /**
     * 悬浮控件顶部拖动按钮
     */
    private var topImg: ImageView
    /**
     * 父控件layoutParam用于设置marginTop控制上边距
     */
    var param:FrameLayout.LayoutParams
    /**
     * 列表控件layoutParam，用于设置列表高度使列表都可滑动至底部
     */
    lateinit var listParam:FrameLayout.LayoutParams
    /**
     * 列表控件
     */
    private lateinit var recyclerView: RecyclerView

    /**
     * 按下开始y坐标
     */
    private var startY = 0f
    private var startX = 0f
    /**
     * 拖动/动画执行时的当前y坐标
     */
    private var currentY = 0

    /**
     * 移动多远后执行动画切换type
     */
    var changeOffset = 130

    /**
     * 父控件顶边距
     */
    private var topMargin = 0
    /**
     * 列表控件最大高度
     */
    var maxHeight = 0

    /**
     * 半屏时的顶边距
     */
    private var halfMargin = 0
    /**
     * 半屏时的列表高度
     */
    var halfHeight = dp2px(350f).toInt()

    /**
     * 最小化时的顶边距，最小不可见时设置大于屏幕高度即可
     */
    private var bottomMargin = 0
    /**
     * 最小化时的列表高度
     */
    private var minHeight = dp2px(100f).toInt()

    /**
     * 底部到半屏时的动画时间
     */
    private var minToHalfTime = 400L
    /**
     * 半屏到全屏的动画时间
     */
    private var halfToMaxTime = 700L

    /**
     * 手指按下时间
     */
    private var touchDownTime = 0L
    /**
     * 手指按下时的marginTop
     */
    private var touchDownMargin = 0

    /**
     * 当前的状态
     */
    private var type = BottomSheetBehavior.STATE_HIDDEN//0 收起, 1 半屏, 2 全屏

    /**
     * 事件回调
     */
    var bottomSheetCallback: DiscoverBottomSheetCallback? = null


    constructor(parent: FrameLayout, topAnchor: View, activity: Activity) {
        this.parent = parent


        topImg = parent.findViewById(R.id.anim_drag_img)
        param = parent.layoutParams as FrameLayout.LayoutParams

        if(topAnchor.height == 0){//未布局好时延迟500ms初始化尺寸数据
            topAnchor.postDelayed({
                initSize(topAnchor, activity)
            }, 500)
        } else {
            initSize(topAnchor, activity)
        }


        initRecy()

        topImg.setOnTouchListener(object :View.OnTouchListener{
            override fun onTouch(v: View?, event: MotionEvent?): Boolean {
                if (event != null) {
                    return dealWithTouchEvent(event)
                }
                return true
            }

        })
    }

    private var isDragging = false

    private fun dealWithTouchEvent(event: MotionEvent): Boolean{
        when(event.action) {
            MotionEvent.ACTION_DOWN -> {
                startY = event.getY(0)
                startX = event.getX(0)
                touchDownTime = System.currentTimeMillis()
                touchDownMargin = param.topMargin
            }
            MotionEvent.ACTION_MOVE -> {
                if (isDragging || Math.abs(event.getY() - startY) > Math.abs(event.getX() - startX)) {
                    isDragging = true
                } else {
                    return false
                }

                currentY = param.topMargin

                param.topMargin = param.topMargin + (event.getY(0) - startY).toInt()
                parent.layoutParams = param

                //param.topMargin包含topAnchor的高度及marginTop，所以加上最初的topMargin
                listParam.height = maxHeight - param.topMargin -topImg.height + topMargin
                recyclerView.layoutParams = listParam

                bottomSheetCallback?.onDragging(this@DragFloatWidget.parent, topMargin + maxHeight - param.topMargin, type)
            }
            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
                if (!isDragging) {
                    return false
                }
                isDragging = false
                if((System.currentTimeMillis() - touchDownTime) < 200 && abs(touchDownMargin - param.topMargin) < 10){
                    //点击事件
                    bottomSheetCallback?.onHeaderClick(this@DragFloatWidget.parent, listParam.height + topImg.height, type)
                    return true
                }


                var time = 0L
                val destination = when(type) {
                    BottomSheetBehavior.STATE_HIDDEN ->{
                        if (param.topMargin < (bottomMargin - changeOffset)) {
                            type = BottomSheetBehavior.STATE_HALF_EXPANDED

                            time = ((param.topMargin - halfMargin).toFloat() / (bottomMargin - halfMargin) * minToHalfTime).toLong()

                            halfMargin
                        } else {

                            time = ((bottomMargin - param.topMargin).toFloat() / (bottomMargin - halfMargin) * minToHalfTime).toLong()

                            bottomMargin
                        }
                    }
                    BottomSheetBehavior.STATE_HALF_EXPANDED -> {
                        if (param.topMargin < (halfMargin - changeOffset)) {
                            type = BottomSheetBehavior.STATE_EXPANDED

                            time = ((param.topMargin - topMargin).toFloat() / (halfMargin - topMargin) * halfToMaxTime).toLong()

                            topMargin
                        } else if (param.topMargin > (halfMargin + changeOffset)){
                            type = BottomSheetBehavior.STATE_HIDDEN

                            time = ((bottomMargin - param.topMargin).toFloat() / (bottomMargin - halfMargin) * minToHalfTime).toLong()

                            bottomMargin
                        } else {
                            time = ((abs(param.topMargin - halfMargin)).toFloat() / halfMargin * minToHalfTime).toLong()


                            halfMargin
                        }
                    }
                    BottomSheetBehavior.STATE_EXPANDED -> {
                        if (param.topMargin > topMargin + changeOffset) {
                            type = BottomSheetBehavior.STATE_HALF_EXPANDED

                            time = ((halfMargin - param.topMargin).toFloat() / (halfMargin - topMargin) * halfToMaxTime).toLong()

                            halfMargin
                        } else {
                            time = ((abs(param.topMargin - topMargin)).toFloat() / topMargin * halfToMaxTime).toLong()

                            topMargin
                        }
                    }
                    else -> bottomMargin
                }

                startFling(time , param.topMargin,  destination)
            }
        }
        return true
    }

    /**
     * 计算相关尺寸
     */
    private fun initSize(topAnchor: View, activity: Activity) {
        val location = IntArray(2)
        topAnchor.getLocationInWindow(location)

        val dm = DisplayMetrics()
        activity.windowManager.getDefaultDisplay().getRealMetrics(dm);
//        var dwidth = dm.widthPixels;
        val dheight = dm.heightPixels

        val marginTop = location[1] + topAnchor.height

        this.maxHeight = dheight - marginTop

        topMargin = topAnchor.top + topAnchor.height
        halfMargin = topMargin + maxHeight - halfHeight
        bottomMargin = topMargin + maxHeight - minHeight
        param.topMargin = bottomMargin//开始为hidden隐藏,设置marginTop为bottomMargin


        param.height = this.maxHeight
        parent.layoutParams = param


        listParam.height = maxHeight - topImg.height
        recyclerView.layoutParams = listParam
    }

    /**
     * 开始执行动画
     */
    private fun startFling(time: Long, start: Int, destination: Int) {
        val valueAnimator: ValueAnimator =
            ValueAnimator.ofInt(start, destination).setDuration(if (time > 0) time else 100)
        valueAnimator.interpolator = LinearInterpolator()

        currentY = start
        valueAnimator.addUpdateListener { animation ->
            param.topMargin = animation.animatedValue as Int
            parent.layoutParams = param

            listParam.height = (maxHeight - param.topMargin -topImg.height + topMargin)
            recyclerView.layoutParams = listParam

            bottomSheetCallback?.onFling(this@DragFloatWidget.parent,topMargin + maxHeight - param.topMargin, type)
            currentY = param.topMargin
        }

        valueAnimator.doOnEnd {
            bottomSheetCallback?.onAnimEnd(parent, topMargin + maxHeight - param.topMargin, type)
            val location = IntArray(2)
            recyclerView.getLocationInWindow(location)

            when(type) {
                BottomSheetBehavior.STATE_EXPANDED -> {
                    topImg.setImageResource(R.mipmap.community_discover_ic_arrow_grey)
                    topImg.setPadding(0, dp2px(10f).toInt(), 0, dp2px(15f).toInt())
                }
                else -> {
                    topImg.setImageResource(R.mipmap.community_discover_ic_line_grey)
                    topImg.setPadding(0, dp2px(13f).toInt(), 0, dp2px(18f).toInt())
                }
            }
        }

        valueAnimator.start()
    }

    /**
     * 初始化列表控件
     */
    private fun initRecy() {
        recyclerView = parent.findViewById(R.id.drag_recy)
        listParam = recyclerView.layoutParams as FrameLayout.LayoutParams
        recyclerView.layoutManager = LinearLayoutManager(parent.context)
//        recyclerView.adapter = AnimAdapter()
        recyclerView.adapter = TabListAdapter()
    }

    /**
     * 滑动到某一状态
     */
    fun animToState(state:Int){
        if (state == type) {
            return
        }
        when(state){
            BottomSheetBehavior.STATE_HIDDEN -> {
                type = BottomSheetBehavior.STATE_HIDDEN
                startFling(300, param.topMargin, bottomMargin)
            }
            BottomSheetBehavior.STATE_HALF_EXPANDED -> {
                type = BottomSheetBehavior.STATE_HALF_EXPANDED
                startFling(300, param.topMargin, halfMargin)
            }
            BottomSheetBehavior.STATE_EXPANDED -> {
                type = BottomSheetBehavior.STATE_EXPANDED
                startFling(300, param.topMargin, topMargin)
            }
        }
    }

    private fun dp2px(dp: Float): Float {
        val r = Resources.getSystem()
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.displayMetrics)
    }
}